package Client;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.ArrayList;

/**
 * Used as a gateway for Client, Listener, Sender and GUI.
 * 
 * @author PZK
 * 
 */
public class ClientSocket {

	private boolean isLoggedIn = false;
	private int timeOut = 0;
	private int timeOutMax = 10;
	@SuppressWarnings("unused")
	private Listener listener = null; //for future reference.
	private Sender sender = null;
	private Socket socket = null;
	private GUI gui = null;

	private final String SYSTEM_CODE = this.toString();
	private final String SYSTEM_REGEX = "~!~";
	
	private Client client;

	public ClientSocket(Client client){
		this.client = client;
	}
	/**
	 * Creates a new Socket and tries to connect to servername and port.
	 * 
	 * @param servername
	 * @param port
	 * @throws IOException
	 */
	public void connect(String servername, int port) throws IOException {

		socket = new Socket(servername, port);
		listener = new Listener(this, new BufferedReader(new InputStreamReader(
				socket.getInputStream())));
		sender = new Sender(new PrintWriter(new OutputStreamWriter(
				socket.getOutputStream())));

		sendGreeting();

	}

	/**
	 * Sends a request for logging in to the server.
	 * 
	 * @param username
	 * @param password
	 * @throws Exception
	 */
	public void logIn(String username, String password) throws Exception {

		if (!isLoggedIn) {
			sender.send(SYSTEM_CODE + SYSTEM_REGEX + "LOGIN" + SYSTEM_REGEX
					+ username + SYSTEM_REGEX + password);
			for (int i = 0; i < timeOutMax; i++) {
				Thread.sleep(timeOut);
				if (isLoggedIn)
					break;
			}
		}

		if (!isLoggedIn)
			throw new Exception("Username or password is wrong.");

	}

	/**
	 * Handles all incoming messages from the server.
	 * 
	 * @param message
	 */
	public void messageReceived(String message) {

		System.out.println("CLIENT: MESSAGE RECEIVED: " + message);
		if (message.contains(SYSTEM_CODE)) {
			message = message.substring(SYSTEM_CODE.length()
					+ SYSTEM_REGEX.length());
			String[] split = message.split(SYSTEM_REGEX);
			switch (split[0]) {
			case "LOGIN": {
				isLoggedIn = split[1].contentEquals("TRUE") ? true : false;
			}
				break;
			case "GET_ALL_PROJECTS": {
				setAllProjects(toArrayList(split, 1));
			}
				break;
			case "GET_ALL_USERS": {
				setAllUsers(toArrayList(split, 1));
			}
				break;
			case "GET_OFFLINE_USERS": {
				setOfflineUsers(toArrayList(split, 1));
			}
				break;
			case "GET_PROJECT_USERS": {
				setProjectUsers(toArrayList(split, 1));
			}
				break;
			case "SEND_MESSAGE_TO_CLIENT": {
				System.out.println(split[1] + "-> " + split[2]);
				gui.write(split[1], split[2]);
			}
				break;
			case "SEND_MESSAGE_TO_PROJECT": {
				System.out.println(split[1] + "-> " + split[2]);
				gui.write(split[1], split[2]);
			}
				break;
			default: {
				System.out.println("CLIENT: UNKNOWN SYSTEM COMMAND: "
						+ split[0]);
			}
				break;
			}
		} else {
			System.out.println(message);
		}

	}

	/**
	 * @param subject
	 *            - client name.
	 * @param message
	 */
	public void sendMessageToClient(String subject, String message) {

		sender.send(SYSTEM_CODE + SYSTEM_REGEX + "SEND_MESSAGE_TO_CLIENT"
				+ SYSTEM_REGEX + subject + SYSTEM_REGEX + message);

	}

	/**
	 * @param subject
	 *            - project name.
	 * @param message
	 */
	public void sendMessageToProject(String subject, String message) {

		sender.send(SYSTEM_CODE + SYSTEM_REGEX + "SEND_MESSAGE_TO_PROJECT"
				+ SYSTEM_REGEX + subject + SYSTEM_REGEX + message);

	}

	/**
	 * Sends initial messages to server.
	 */
	private void sendGreeting() {

		sender.send(SYSTEM_CODE);
		sender.send(SYSTEM_REGEX);

	}

	public void userIsLoggedIn() {

		requestAllProjects();
		requestAllUsers();

	}

	public void requestAllProjects() {

		sender.send(SYSTEM_CODE + SYSTEM_REGEX + "GET_ALL_PROJECTS");

	}

	public void requestAllUsers() {

		sender.send(SYSTEM_CODE + SYSTEM_REGEX + "GET_ALL_USERS");

	}

	public void requestProjectUsers(String project) throws Exception {

		if (isLoggedIn)
			sender.send(SYSTEM_CODE + SYSTEM_REGEX + "GET_PROJECT_USERS"
					+ SYSTEM_REGEX + project);
		else
			throw new Exception("USER NOT LOGGED IN YET!");

	}

	private void setAllProjects(ArrayList<String> projects) {

		gui.setGroupChats(projects);

	}

	private void setAllUsers(ArrayList<String> users) {

		gui.setPeopleChats(users);

	}

	private void setOfflineUsers(ArrayList<String> users) {

		gui.updateOfflinePeople(users);

	}

	private void setProjectUsers(ArrayList<String> users) {

		gui.showPeopleChats(users);

	}

	private ArrayList<String> toArrayList(String[] source, int beginWith) {

		ArrayList<String> result = new ArrayList<String>();

		for (int i = beginWith; i < source.length; i++) {

			result.add(source[i]);

		}

		return result;

	}

	public boolean loggedIn() {

		return isLoggedIn;

	}

	public void setTimeout(int timeout) {

		this.timeOut = timeout;

	}

	public void setGUI(GUI gui) {

		if (this.gui == null) {
			this.gui = gui;
		}

	}
	public void disconnect(){
		gui.close();
		client.disconnect();
	}
	
}
